package com.ck.encrypt.controller;

import com.ck.common.constant.AjaxResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


/**
 * @author ck
 * @date 2023/9/1 11:32
 */


/**
 * 接口加签
 */
@RestController
@Slf4j
public class InterFaceEncryptController {

    /**
     * 这里密钥双方共享同一份(妥善保管)
     * @param map
     * @return
     */

    /**
     * 接口加签的的目的是: 验证数据的完整性和来源合法性，而不是加密数据(如支付领域的接口)
     * 接口加签实现思路:
     * 1、将需要传输的参数自然排序后与security拼接在一起，然后通过DigestUtils.md5Hex()通过MD5编码后生成16进制的签名
     * 2、服务端接收到请求参数，去掉签名后重复（1） 操作后，将生成的签名与接收参数种的签名相比，如签名不一样则参数有可能被篡改了or时间戳过期了等，反之则解签成功。
     * @param map
     * @return
     */

    @PostMapping("/encrypt")
    public AjaxResult signTest(@RequestBody Map<String,Object> map){
        String security="xxxxxxxxxxx";
        int timestamp = (int) map.get("timestamp");

        int currentTimeMillis = (int) (System.currentTimeMillis() / 1000);      // 当前时间的秒级时间戳;
        int maxTimestampDifference = 30; // 允许的最大时间差，单位：秒


        if (currentTimeMillis-timestamp>maxTimestampDifference){
            return AjaxResult.error("时间戳过期");
        }

        //验证签名
       boolean verifySignature = verifySignature(map,security);

        if (verifySignature){
            log.info("Signature is valid . Request is legitimate");
            return AjaxResult.success("签名验证成功");
        }
        return AjaxResult.error("Signature is invalid. Request may be tampered");
    }

    private boolean verifySignature(Map<String,Object> map,String security) {
        String sign = (String) map.get("sign");
        map.remove("sign");   //移除签名字段
        String calculatedSign = getSortedContent(map, security);

        return sign.equals(calculatedSign);

    }
    
    private String getSortedContent(Map<String,Object> map,String security){
        List<String> keyList = map.keySet().stream().collect(Collectors.toList());
        Collections.sort(keyList);

        StringBuffer sb = new StringBuffer();
        for (String key : keyList) {
            sb.append(key);
            sb.append(map.get(key));
        }
        sb.append(security);
        return DigestUtils.md5Hex(sb.toString());

    }
}
